﻿namespace S7.Net.Types
{
    using S7.Net;
    using System;
    using System.Reflection;

    public static class Class
    {
        public static void FromBytes(object sourceClass, Type classType, byte[] bytes)
        {
            if ((bytes != null) && (bytes.Length == GetClassSize(classType)))
            {
                int index = 0;
                int num2 = 0;
                double d = 0.0;
                PropertyInfo[] properties = sourceClass.GetType().GetProperties();
                foreach (PropertyInfo info in properties)
                {
                    byte[] buffer;
                    switch (info.PropertyType.Name)
                    {
                        case "Boolean":
                            index = (int) Math.Floor(d);
                            num2 = (int) ((d - index) / 0.125);
                            if ((bytes[index] & ((int) Math.Pow(2.0, (double) num2))) == 0)
                            {
                                break;
                            }
                            info.SetValue(sourceClass, true, null);
                            goto Label_016B;

                        case "Byte":
                        {
                            d = Math.Ceiling(d);
                            info.SetValue(sourceClass, bytes[(int) d], null);
                            d++;
                            continue;
                        }
                        case "Int16":
                        {
                            d = Math.Ceiling(d);
                            if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                            {
                                d++;
                            }
                            ushort input = Word.FromBytes(bytes[((int) d) + 1], bytes[(int) d]);
                            info.SetValue(sourceClass, input.ConvertToShort(), null);
                            d += 2.0;
                            continue;
                        }
                        case "UInt16":
                        {
                            d = Math.Ceiling(d);
                            if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                            {
                                d++;
                            }
                            info.SetValue(sourceClass, Word.FromBytes(bytes[((int) d) + 1], bytes[(int) d]), null);
                            d += 2.0;
                            continue;
                        }
                        case "Int32":
                        {
                            d = Math.Ceiling(d);
                            if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                            {
                                d++;
                            }
                            uint num5 = DWord.FromBytes(bytes[((int) d) + 3], bytes[((int) d) + 2], bytes[((int) d) + 1], bytes[(int) d]);
                            info.SetValue(sourceClass, num5.ConvertToInt(), null);
                            d += 4.0;
                            continue;
                        }
                        case "UInt32":
                        {
                            d = Math.Ceiling(d);
                            if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                            {
                                d++;
                            }
                            info.SetValue(sourceClass, DWord.FromBytes(bytes[(int) d], bytes[((int) d) + 1], bytes[((int) d) + 2], bytes[((int) d) + 3]), null);
                            d += 4.0;
                            continue;
                        }
                        case "Double":
                        {
                            d = Math.Ceiling(d);
                            if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                            {
                                d++;
                            }
                            info.SetValue(sourceClass, S7.Net.Types.Double.FromByteArray(new byte[] { bytes[(int) d], bytes[((int) d) + 1], bytes[((int) d) + 2], bytes[((int) d) + 3] }), null);
                            d += 4.0;
                            continue;
                        }
                        default:
                            goto Label_042E;
                    }
                    info.SetValue(sourceClass, false, null);
                Label_016B:
                    d += 0.125;
                    continue;
                Label_042E:
                    buffer = new byte[GetClassSize(info.PropertyType)];
                    if (buffer.Length != 0)
                    {
                        Buffer.BlockCopy(bytes, (int) Math.Ceiling(d), buffer, 0, buffer.Length);
                        object obj2 = Activator.CreateInstance(info.PropertyType);
                        FromBytes(obj2, info.PropertyType, buffer);
                        info.SetValue(sourceClass, obj2, null);
                        d += buffer.Length;
                    }
                }
            }
        }

        public static int GetClassSize(Type classType)
        {
            double a = 0.0;
            PropertyInfo[] properties = classType.GetProperties();
            foreach (PropertyInfo info in properties)
            {
                switch (info.PropertyType.Name)
                {
                    case "Boolean":
                        a += 0.125;
                        break;

                    case "Byte":
                        a = Math.Ceiling(a) + 1.0;
                        break;

                    case "Int16":
                    case "UInt16":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 2.0;
                        break;

                    case "Int32":
                    case "UInt32":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 4.0;
                        break;

                    case "Float":
                    case "Double":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 4.0;
                        break;

                    default:
                        a += GetClassSize(info.PropertyType);
                        break;
                }
            }
            return (int) a;
        }

        public static byte[] ToBytes(object sourceClass)
        {
            byte[] buffer = new byte[GetClassSize(sourceClass.GetType())];
            byte[] buffer2 = null;
            int index = 0;
            int num3 = 0;
            double d = 0.0;
            PropertyInfo[] properties = sourceClass.GetType().GetProperties();
            foreach (PropertyInfo info in properties)
            {
                buffer2 = null;
                switch (info.PropertyType.Name)
                {
                    case "Boolean":
                        index = (int) Math.Floor(d);
                        num3 = (int) ((d - index) / 0.125);
                        if (!((bool) info.GetValue(sourceClass, null)))
                        {
                            break;
                        }
                        buffer[index] = (byte) (buffer[index] | ((byte) Math.Pow(2.0, (double) num3)));
                        goto Label_018F;

                    case "Byte":
                        d = (int) Math.Ceiling(d);
                        index = (int) d;
                        buffer[index] = (byte) info.GetValue(sourceClass, null);
                        d++;
                        goto Label_0242;

                    case "Int16":
                        buffer2 = Int.ToByteArray((short) info.GetValue(sourceClass, null));
                        goto Label_0242;

                    case "UInt16":
                        buffer2 = Word.ToByteArray((ushort) info.GetValue(sourceClass, null));
                        goto Label_0242;

                    case "Int32":
                        buffer2 = DInt.ToByteArray((int) info.GetValue(sourceClass, null));
                        goto Label_0242;

                    case "UInt32":
                        buffer2 = DWord.ToByteArray((uint) info.GetValue(sourceClass, null));
                        goto Label_0242;

                    case "Double":
                        buffer2 = S7.Net.Types.Double.ToByteArray((double) info.GetValue(sourceClass, null));
                        goto Label_0242;

                    default:
                        goto Label_0242;
                }
                buffer[index] = (byte) (buffer[index] & ~((byte) Math.Pow(2.0, (double) num3)));
            Label_018F:
                d += 0.125;
            Label_0242:
                if (buffer2 != null)
                {
                    d = Math.Ceiling(d);
                    if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                    {
                        d++;
                    }
                    index = (int) d;
                    for (int i = 0; i < buffer2.Length; i++)
                    {
                        buffer[index + i] = buffer2[i];
                    }
                    d += buffer2.Length;
                }
            }
            return buffer;
        }
    }
}

